package com.example.everying.service.pay.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.everying.constant.OrderConstants;
import com.example.everying.context.UserContext;
import com.example.everying.framework.pay.service.WechatPayService;
import com.example.everying.mapper.pay.PaymentOrderMapper;
import com.example.everying.model.dto.pay.TransactionDto;
import com.example.everying.model.entity.pay.PaymentOrderEntity;
import com.example.everying.model.entity.pay.notify.PaymentNotifyEntity;
import com.example.everying.model.entity.user.UserEntity;
import com.example.everying.model.entity.user.UserBalanceEntity;
import com.example.everying.model.entity.user.UserBalanceTransactionEntity;
import com.example.everying.service.pay.PaymentNotifyService;
import com.example.everying.service.pay.PaymentOrderService;
import com.example.everying.service.user.UserBalanceService;
import com.example.everying.service.user.UserBalanceTransactionService;
import com.example.everying.service.user.UserService;
import com.example.everying.utils.Result;
import com.example.everying.utils.WeChatUtil;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;

@Service
@Slf4j
public class PaymentOrderServiceImpl extends ServiceImpl<PaymentOrderMapper, PaymentOrderEntity> implements PaymentOrderService {

    @Autowired
    private WechatPayService wechatPayService;
    @Autowired
    private UserService userService;
    @Autowired
    private PaymentNotifyService paymentNotifyService;
    @Autowired
    private UserBalanceTransactionService userBalanceTransactionService;
    @Autowired
    private UserBalanceService userBalanceService;


    /**
     * 创建订单
     *
     * @param paymentOrderEntity 支付订单实体，包含订单相关信息
     * @return 返回结果，包含成功或失败信息
     */
    @Transactional
    @Override
    public Result<?> createOrder(PaymentOrderEntity paymentOrderEntity) {
        // 检查订单金额是否为0，如果非0则返回失败结果
        if (paymentOrderEntity.getTotalFee().compareTo(BigDecimal.ZERO) < 1) {
            return Result.fail("最低充值1元");
        }
        // 获取当前用户信息
        UserEntity user = UserContext.getUser();
        // 检查用户是否存在，如果不存在则返回失败结果
        if (user == null) {
            return Result.fail("用户不存在");
        }
        // 检查用户是否绑定微信，如果未绑定则返回失败结果
        if (user.getOpenId() == null) {
            return Result.fail("用户未绑定微信");
        }
        // 1. 创建订单
        // 设置订单号
        paymentOrderEntity.setOutTradeNo(WeChatUtil.generateTradeNumber(OrderConstants.TRANSACTION_TYPE_PREFIX_DEPOSIT));
        // 设置用户openid
        paymentOrderEntity.setOpenid(user.getOpenId());
        // 设置交易类型
        paymentOrderEntity.setTradeType("JSAPI"); // JSAPI等
        // 设置交易开始时间
        paymentOrderEntity.setTimeStart(LocalDateTime.now());
        paymentOrderEntity.setBody("用户充值");
        paymentOrderEntity.setTradeState(OrderConstants.ORDER_STATUS_CREATE);
        paymentOrderEntity.setTradeStateDesc("订单创建成功");
        // 设置用户ID
        paymentOrderEntity.setUserId(user.getId());
        int save = baseMapper.insert(paymentOrderEntity);
        // 如果订单创建失败，则返回失败结果
        if (save == 0) {
            return Result.fail();
        }
        // openId从用户信息中获取
        // 开始调用第三方的接口
        log.info("开始创建充值订单：{}", paymentOrderEntity);
        PrepayWithRequestPaymentResponse response = wechatPayService.createOrder(paymentOrderEntity.getTotalFee().multiply(BigDecimal.valueOf(100)).intValue(), paymentOrderEntity.getBody(), paymentOrderEntity.getOutTradeNo(), paymentOrderEntity.getOpenid());
       log.info("创建充值订单响应：{}", response);
        // 检查微信接口调用结果，如果失败则返回失败结果
        if (response == null) {
            return Result.fail("调用微信充值失败");
        }
        // 返回成功结果
        return Result.ok(response);
    }

    /**
     * 查询订单
     *
     * @param outTradeNo 订单号
     * @return 返回结果，包含成功或失败信息
     */
    @Override
    public Result<?> queryOrder(String outTradeNo) {
        // 检查订单号是否存在，如果不存在则返回失败结果
        if (outTradeNo == null) {
            return Result.fail("订单号不存在");
        }
        log.info("查询订单：{}", outTradeNo);
        // 构建查询条件
        QueryWrapper<PaymentOrderEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("out_trade_no", outTradeNo);
        // 查询订单信息
        PaymentOrderEntity paymentOrderEntity = baseMapper.selectOne(queryWrapper);
        // 检查订单是否存在，如果不存在则返回失败结果
        if (paymentOrderEntity == null) {
            return Result.fail("订单不存在");
        }
        // 调用微信接口查询订单状态
        Transaction transaction = wechatPayService.queryOrderByOutTradeNo(outTradeNo);
        log.info("查询订单状态：{}", transaction);
        if (transaction == null) {
            return Result.fail("查询订单失败");
        }
        // 返回成功结果
        return Result.ok(transaction);
    }


    /**
     * 处理支付回调通知
     * 该方法主要用于处理微信支付的回调通知，验证支付状态并更新相关订单信息
     * 如果支付成功，还会更新用户的余额并记录交易
     *
//     * @param request HttpServletRequest对象，用于获取回调通知的数据
     * @return 返回处理结果，包括成功或失败的信息
     * @throws IOException 如果读取请求数据时发生错误
     */

    @Transactional
    @Override
//    public Result<?> payCallback(TransactionDto request) throws IOException {
//
    public Result<?> payCallback(HttpServletRequest request) throws IOException {
        log.info("处理支付回调通知：{}",  request);
        // 调用服务方法处理支付回调
        Transaction transaction = wechatPayService.payCallback(request);
        log.info("支付回调结果：{}", transaction);
        if (transaction == null) {
            return Result.fail("回调失败");
        }
//        Transaction transaction = new Transaction();
//                BeanUtils.copyProperties(request, transaction);
        // 记录回调
        PaymentNotifyEntity paymentNotifyEntity = savePaymentNotify(transaction);
        log.info("保存回调结果：{}", paymentNotifyEntity);

        String outTradeNo = transaction.getOutTradeNo();
        QueryWrapper<PaymentOrderEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("out_trade_no", outTradeNo);
        PaymentOrderEntity paymentOrderEntity = baseMapper.selectOne(queryWrapper);


        if (paymentOrderEntity == null) {
            log.warn("订单不存在: out_trade_no={}", outTradeNo);
            paymentNotifyEntity.setHandleStatus(OrderConstants.NOTIFY_STATUS_FAIL);
            updatePaymentNotify(paymentNotifyEntity, transaction);
            return Result.fail("订单不存在");
        }

        // 更新订单通用信息
        updatePaymentOrderEntity(paymentOrderEntity, transaction, queryWrapper);

        if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
            log.info("支付成功: out_trade_no={}, openid={}", outTradeNo, paymentOrderEntity.getOpenid());            // 查询订单

            // 支付成功之后查询用户信息
            UserEntity user = userService.getUserById(paymentOrderEntity.getUserId());
            if (user == null) {
                log.info("用户不存在: uid={}", paymentOrderEntity.getUserId());
                return Result.fail("用户不存在");
            }
            // 充值成功之后增加用户余额

            // 更新用户余额
            BigDecimal amountToRecharge = paymentOrderEntity.getTotalFee();
            log.info("充值金额：{}", amountToRecharge);
            boolean isAdd = userBalanceService.addBalance(paymentOrderEntity.getUserId(), amountToRecharge);
            if (!isAdd) {
                return Result.fail("充值失败");
            }
            user.setBalance(user.getBalance().add(paymentOrderEntity.getTotalFee()));
            // 根据openId更新用户余额会修改已注销用户的状态
//            userService.updateUserBalanceByOpenId(user);
            // 记录用户余额交易记录
            saveUserBalanceTransaction(paymentOrderEntity, transaction);

            // 更新回调状态
            paymentNotifyEntity.setHandleStatus(OrderConstants.NOTIFY_STATUS_SUCCESS);
            updatePaymentNotify(paymentNotifyEntity, transaction);

            return Result.ok();
        } else {
            log.info("支付失败: out_trade_no={}", transaction.getOutTradeNo());
            // 更新回调状态
            paymentNotifyEntity.setHandleStatus(OrderConstants.NOTIFY_STATUS_FAIL);
            updatePaymentNotify(paymentNotifyEntity, transaction);
            return Result.ok();
        }
    }

    /**
     * 保存支付通知信息
     * 当支付平台通知服务器支付结果时，调用此方法保存通知信息
     *
     * @param transaction 交易信息对象，包含支付相关的数据
     * @return 返回保存后的支付通知实体对象
     */
    private PaymentNotifyEntity savePaymentNotify(Transaction transaction) {
        PaymentNotifyEntity paymentNotifyEntity = new PaymentNotifyEntity();
        paymentNotifyEntity.setOutTradeNo(transaction.getOutTradeNo());
        paymentNotifyEntity.setNotifyData(transaction.toString());
        paymentNotifyEntity.setNotifyTime(LocalDateTime.now());
        paymentNotifyEntity.setHandleStatus(OrderConstants.NOTIFY_STATUS_WAIT);
        paymentNotifyService.save(paymentNotifyEntity);
        return paymentNotifyEntity;
    }

    /**
     * 更新支付通知信息
     * 在处理支付通知过程中，如果需要更新通知信息的状态或内容，调用此方法
     *
     * @param paymentNotifyEntity 支付通知实体对象，包含需要更新的信息
     * @param transaction         交易信息对象，用于查找对应的支付通知
     */
    private void updatePaymentNotify(PaymentNotifyEntity paymentNotifyEntity, Transaction transaction) {
        QueryWrapper<PaymentNotifyEntity> queryNotifyWrapper = new QueryWrapper<>();
        queryNotifyWrapper.eq("out_trade_no", transaction.getOutTradeNo());
        paymentNotifyService.update(paymentNotifyEntity, queryNotifyWrapper);
    }

    /**
     * 保存用户余额交易记录
     * 在用户充值成功后，调用此方法记录用户的资金流水信息
     *
     * @param paymentOrderEntity 支付订单实体对象，包含用户充值的相关信息
     * @param transaction        交易信息对象，提供交易ID等信息
     */
    private void saveUserBalanceTransaction(PaymentOrderEntity paymentOrderEntity, Transaction transaction) {
        log.info("记录资金流水");
        // 先查一下当前余额
        UserBalanceEntity userBalance = userBalanceService.getBalanceByUserId(paymentOrderEntity.getUserId());
        UserBalanceTransactionEntity userBalanceTransaction = new UserBalanceTransactionEntity();
        userBalanceTransaction.setUserId(paymentOrderEntity.getUserId());
        userBalanceTransaction.setTxId(transaction.getTransactionId());
        userBalanceTransaction.setChangeAmount(paymentOrderEntity.getTotalFee());
        userBalanceTransaction.setBalanceSnapshot(paymentOrderEntity.getTotalFee().add(userBalance.getAvailableAmount()));
        userBalanceTransaction.setTxStatus(OrderConstants.TX_STATUS_SUCCESS);
        userBalanceTransaction.setTxType(OrderConstants.TYPE_USER_RECHARGE);
        userBalanceTransaction.setUserType(OrderConstants.USER_TYPE_USER);
        userBalanceTransaction.setRemark("用户充值");
        userBalanceTransaction.setType(OrderConstants.ORDER_TYPE_RECHARGE);
        userBalanceTransactionService.save(userBalanceTransaction);
    }

    // 封装订单更新逻辑
    private void updatePaymentOrderEntity(PaymentOrderEntity entity, Transaction transaction,
                                          Wrapper<PaymentOrderEntity> queryWrapper) {
        entity.setTransactionId(transaction.getTransactionId());
        entity.setTradeState(transaction.getTradeState().toString());
        entity.setTradeStateDesc(transaction.getTradeStateDesc());
        this.update(entity, queryWrapper);
    }
}

